﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Microsoft.TeamFoundation.Client;
using System.Globalization;
using Microsoft.TeamFoundation.VersionControl.Client;
using Microsoft.TeamFoundation.WorkItemTracking.Client;
using Microsoft.TeamFoundation.WorkItemTracking.Controls;
using System.Diagnostics;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using System.Runtime.InteropServices;
using Microsoft.VisualStudio;

namespace Tcvt.Packages
{
    public partial class WorkItemExplorerUserControl : UserControl
    {
        private const string TFS_CUSTOM_USER_AGENT = "Buddy Build Client";
        private const string AREAS_WIQL_TEMPLATE = "SELECT [System.Id], [System.Title], [System.State], [System.AssignedTo], [System.CreatedBy], [System.CreatedDate], [System.ChangedDate], [System.WorkItemType], [System.IterationPath], [System.AreaPath] FROM Workitems WHERE [System.TeamProject] = '{0}' AND [System.AreaPath] UNDER '{1}' ORDER BY [System.ID] DESC";
        private const string ITERATIONS_WIQL_TEMPLATE = "SELECT [System.Id], [System.Title], [System.State], [System.AssignedTo], [System.CreatedBy], [System.CreatedDate], [System.ChangedDate], [System.WorkItemType], [System.AreaPath], [System.IterationPath] FROM Workitems WHERE [System.TeamProject] = '{0}' AND [System.IterationPath] UNDER '{1}' ORDER BY [System.ID] DESC";
        private const int MAX_RESULTS_DISPLAYED = -1; // -1 = unlimited.
        private const string RESULTS_COUNT_TEMPLATE = "Displayed: {0} (Total: {1})";

        private string _tfsHost;
        private string[] _registeredHostNames;
        private TeamFoundationServer _tfs;
        private VersionControlServer _versionControl;
        private WorkItemStore _store;
        private WorkItemCollection _workItemCollection;
        private string[] _queryColumns;
        private bool _useCachedTeamProjects = true;
        private string _teamProjectName = string.Empty;
        private bool _initializing = true;
        private bool _updatingHost = false;
        private int _maxResultsDisplayed = MAX_RESULTS_DISPLAYED;
        private string _lastWiql;
        private List<int> _cachedItems;

        public WorkItemExplorerUserControl()
        {
            InitializeComponent();

            if (!DesignMode)
            {
                InitializePackage();

                InitializeHosts();
            }
        }

        public WorkItemExplorerUserControl(TcvtVsPackage package)
        {
            InitializeComponent();

            if (!DesignMode)
            {
                InitializeHosts();

                _package = package;
            }
        }

        public WorkItemCollection WorkItemCollection
        {
            get
            {
                return _workItemCollection;
            }
        }

        private void InitializeHosts()
        {
            try
            {
                _initializing = true;

                _registeredHostNames = Utils.RegisteredTfsServers();

                if (_registeredHostNames != null && _registeredHostNames.Length > 0)
                {
                    this.tfsToolStripComboBox.Items.Clear();
                    this.tfsToolStripComboBox.Items.AddRange(_registeredHostNames);

                    string tfsHost = string.Empty;
                    if (!string.IsNullOrEmpty(_package.WorkItemExplorerGeneralOptions.TfsHostUri))
                        tfsHost = _package.WorkItemExplorerGeneralOptions.TfsHostUri;

                    if (string.IsNullOrEmpty(tfsHost))
                        tfsHost = _tfsHost;

                    // locate host in list if host is specified.
                    if (!string.IsNullOrEmpty(tfsHost))
                    {
                        if (Utils.StringArrayContainsValue(_registeredHostNames, tfsHost) >= 0)
                        {
                            _initializing = false;
                            this.tfsToolStripComboBox.Text = tfsHost;
                        }
                        else
                        {
                            _tfsHost = string.Empty;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Utils.LogMessage(string.Format("WorkItemExplorerUserControl:InitializeHosts: Error authenticating: Message: {0}", ex.Message), LogType.Error);
                Utils.LogMessage(string.Format("WorkItemExplorerUserControl:InitializeHosts: Error authenticating: {0}", ex.StackTrace), LogType.Error);
                Utils.ShowErrorMessageBox(string.Format("Error initializing Work Item Explorer user control:\r\n\r\n{0}", ex.Message));
            }
            finally
            {
                _initializing = false;
            }
        }

        private bool InitializeSourceControl(int selectedHostIndex)
        {
            // try to get a TFS instance using current credentials:
            if (selectedHostIndex < 0)  // first time or no selection
                return true;

            string tfsHost = string.Empty;
            string newHost = tfsToolStripComboBox.SelectedItem.ToString();
            if (string.Compare(newHost, _tfsHost, true) != 0)
            {
                tfsHost = newHost;
            }
            else
                return true;

            Utils.LogMessage(string.Format(CultureInfo.CurrentCulture, "WorkItemExplorerUserControl:InitializeSourceControl: TFS Host: {0}", tfsHost == null ? string.Empty : tfsHost));

            try
            {
                this.splitContainer1.Enabled = false;
                this.tfsToolStripComboBox.Enabled = false;
                this.projectToolStripComboBox.Enabled = false;
                this.queryToolStripProgressBar.Visible = true;
                Application.DoEvents();

                TfsConnection.ApplicationName = TFS_CUSTOM_USER_AGENT;
                TeamFoundationServer tfs = TeamFoundationServerFactory.GetServer(tfsHost);

                //tfs = new TeamFoundationServer(tfsHost, new UICredentialsProvider());
                try
                {
                    tfs.EnsureAuthenticated();
                }
                catch (Exception ex)
                {
                    Utils.LogMessage(string.Format("WorkItemExplorerUserControl:InitializeSourceControl: Error authenticating: Message: {0}", ex.Message), LogType.Error);
                    Utils.LogMessage(string.Format("WorkItemExplorerUserControl:InitializeSourceControl: Error authenticating: {0}", ex.StackTrace), LogType.Error);
                    Utils.ShowErrorMessageBox(string.Format("Error authenticating:\r\n\r\n{0}\r\n\r\n" +
                        "Please connect to the TFS Server using Team Explorer and try again.",
                        ex.Message));
                    return false;
                }

                VersionControlServer versionControl = (VersionControlServer)tfs.GetService(typeof(VersionControlServer));
                if (versionControl == null)
                {
                    Utils.LogMessage(string.Format(CultureInfo.CurrentCulture, "WorkItemExplorerUserControl:InitializeSourceControl:Failed to initialize version control for the TFS URL: {0}.",
                        tfsHost));
                    Utils.ShowErrorMessageBox(string.Format(CultureInfo.CurrentCulture, "Failed to initialize version control for the TFS URL: {0}.",
                        tfsHost));
                    return false;
                }

                // Save the settings.
                _tfs = tfs;
                _versionControl = versionControl;
                _tfsHost = tfsHost;

                this.ResetState();

                // Populate team project names:
                this.InitializeProjects(-1);
            }
            finally
            {
                this.queryToolStripProgressBar.Visible = false;
                this.projectToolStripComboBox.Enabled = true;
                this.tfsToolStripComboBox.Enabled = true;
                this.splitContainer1.Enabled = true;
                Application.DoEvents();
            }
            return true;
        }

        private bool InitializeProjects(int selectedTeamProjectIndex)
        {
            try
            {
                if (selectedTeamProjectIndex < 0)   // first time.
                {
                    string[] teamProjectNames = this.GetAllTeamProjectNames(false);

                    if (teamProjectNames == null || teamProjectNames.Length <= 0)
                    {
                        Utils.LogMessage("WorkItemExplorerUserControl:InitializeProjects: No TeamProjectNames found.", LogType.Error);
                        Utils.ShowErrorMessageBox(
                            "Failed to retrieve the Team Projects for the selected TFS Host.\r\n" +
                            "Please make sure you have permissions in the selected TFS Host or select " +
                            "a different host.");
                        return false;
                    }

                    this.projectToolStripComboBox.Items.Clear();
                    this.projectToolStripComboBox.Items.AddRange(teamProjectNames);

                    // locate host in list if host is specified.
                    if (teamProjectNames.Length == 1) // only one project? then auto-select it.
                    {
                        _teamProjectName = teamProjectNames[0];
                        this.projectToolStripComboBox.Text = _teamProjectName;
                        this.projectToolStripComboBox.SelectedIndex = 0;
                    }
                    else if (!string.IsNullOrEmpty(_package.WorkItemExplorerGeneralOptions.TeamProjectName))
                    {
                        string teamProjectName = _package.WorkItemExplorerGeneralOptions.TeamProjectName;
                        if (teamProjectNames.Contains(teamProjectName))
                        {
                            _teamProjectName = teamProjectName;
                            this.projectToolStripComboBox.Text = teamProjectName;
                        }
                        else
                        {
                            _teamProjectName = string.Empty;
                        }
                    }
                    else
                    {
                        _teamProjectName = string.Empty;
                    }
                }
                else
                {
                    _teamProjectName = this.projectToolStripComboBox.SelectedItem.ToString();
                }

                this.InitializePanes();

                return true;
            }
            catch (Exception ex)
            {
                Utils.LogMessage(string.Format("WorkItemExplorerUserControl:InitializeProjects: Error initializing team projects list: Message: {0}", ex.Message), LogType.Error);
                Utils.LogMessage(string.Format("WorkItemExplorerUserControl:InitializeProjects: Error initializing team projects list: {0}", ex.StackTrace), LogType.Error);
                Utils.ShowErrorMessageBox(string.Format("Error initializing team projects list:\r\n\r\n{0}",
                    ex.Message));
                //Utils.ShowErrorMessageBox(string.Format("Error reading BuildDefinitionsTeamProjectName setting:\r\n\r\n{0}\r\n{1}",
                //    ex.Message,
                //    ex.StackTrace));
                return false;
            }
        }

        private void InitializePanes()
        {
            if (string.IsNullOrEmpty(_teamProjectName))
            {
                this.areasTreeView.Nodes.Clear();
                this.iterationsTreeView.Nodes.Clear();
                this.resultsDataGridView.Rows.Clear();
                this.resultsDataGridView.Columns.Clear();
                _store = null;
                _workItemCollection = null;
                UpdateResultsCount();
                return;
            }

            // initialize areas and iterations.
            if (_store == null)
                _store = (WorkItemStore)_tfs.GetService(typeof(WorkItemStore));

            NodeCollection areaRootNodes = _store.Projects[_teamProjectName].AreaRootNodes;
            NodeCollection iterationRootNodes = _store.Projects[_teamProjectName].IterationRootNodes;

            this.InitializeAreas(areaRootNodes);
            this.InitializeIterations(iterationRootNodes);
        }

        private void InitializeAreas(NodeCollection areaRootNodes)
        {
            this.areasTreeView.Nodes.Clear();
            if (areaRootNodes.Count > 0)
                NodeCollectionToTreeNodeCollection(areaRootNodes, this.areasTreeView.Nodes);
            //else
            //    this.areasTreeView.Nodes.Add("Areas");

            this.areasTabPage.Text = "Areas";
        }

        private void InitializeIterations(NodeCollection iterationRootNodes)
        {
            this.iterationsTreeView.Nodes.Clear();
            if (iterationRootNodes.Count > 0)
                NodeCollectionToTreeNodeCollection(iterationRootNodes, this.iterationsTreeView.Nodes);
            //else
            //    this.iterationsTreeView.Nodes.Add("Iterations");

            this.iterationsTabPage.Text = "Iterations";
        }

        private TeamProject[] GetAllTeamProjects()
        {
            Utils.LogMessage(string.Format("WorkItemExplorerUserControl:GetAllTeamProjects: '{0}'.", _useCachedTeamProjects ? "Use Cached Copy" : "Refresh from TFS"),
                LogType.Informational);
            return _versionControl.GetAllTeamProjects(!_useCachedTeamProjects);
        }

        private string[] GetAllTeamProjectNames(bool onlyProjectsWithBuildDefinitions)
        {
            TeamProject[] teamProjects = this.GetAllTeamProjects();
            string[] teamProjectNames = null;
            List<string> teamProjectsList = new List<string>();
            if (teamProjects == null || teamProjects.Length <= 0)
                return null;

            for (int i = 0; i < teamProjects.Length; i++)
            {
                if (onlyProjectsWithBuildDefinitions)
                {
                    teamProjectsList.Add(teamProjects[i].Name);
                }
                else
                {
                    teamProjectsList.Add(teamProjects[i].Name);
                }
            }

            if (teamProjectsList.Count <= 0)
                return null;

            teamProjectNames = new string[teamProjectsList.Count];
            teamProjectsList.CopyTo(teamProjectNames);
            return teamProjectNames;
        }

        private void tfsToolStripComboBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (_updatingHost)
                return;

            if (!_initializing)
            {
                _updatingHost = true;
                try
                {
                    if (!this.InitializeSourceControl(this.tfsToolStripComboBox.SelectedIndex))
                    {
                        // revert the combo box to the original selection.
                        this.tfsToolStripComboBox.Text = _tfsHost;
                    }
                }
                catch (Exception ex)
                {
                    Utils.LogMessage(string.Format("WorkItemExplorerUserControl:tfsToolStripComboBox_SelectedIndexChanged: Error initializing: Message: {0}", ex.Message), LogType.Error);
                    Utils.LogMessage(string.Format("WorkItemExplorerUserControl:tfsToolStripComboBox_SelectedIndexChanged: Error initializing: {0}", ex.StackTrace), LogType.Error);
                    Utils.ShowErrorMessageBox(string.Format("Error initializing:\r\n\r\n{0}", ex.Message));
                }
                finally
                {
                    _updatingHost = false;
                }
            }
        }

        private void ResetState()
        {
            _store = null;
            _workItemCollection = null;
            _queryColumns = null;
            _lastWiql = string.Empty;
            _cachedItems = new List<int>();

            this.resultsDataGridView.VirtualMode = false;
            this.resultsDataGridView.Rows.Clear();
            this.resultsDataGridView.Columns.Clear();

            this.pathToolStripTextBox.Text = string.Empty;
            this.pathToolStripTextBox.Tag = string.Empty;

            UpdateResultsCount();
        }

        private void projectToolStripComboBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (!_initializing)
            {
                try
                {
                    if (string.Compare(_teamProjectName, this.projectToolStripComboBox.Text, true) == 0)
                        return;

                    this.splitContainer1.Enabled = false;
                    this.areasTreeView.Nodes.Clear();
                    this.iterationsTreeView.Nodes.Clear();
                    this.resultsDataGridView.Rows.Clear();
                    this.resultsDataGridView.Columns.Clear();
                    this.pathToolStripTextBox.Text = string.Empty;
                    this.pathToolStripTextBox.Tag = string.Empty;
                    _store = null;
                    _workItemCollection = null;

                    UpdateResultsCount();

                    this.areasTabPage.Text = "Areas (working...)";
                    this.iterationsTabPage.Text = "Iterations (working...)";

                    Application.DoEvents();

                    _teamProjectName = this.projectToolStripComboBox.Text;

                    this.InitializePanes();
                }
                catch (Exception ex)
                {
                    Utils.LogMessage(string.Format("WorkItemExplorerUserControl:projectToolStripComboBox_SelectedIndexChanged: Error initializing iterations and areas for selected project: Message: {0}", ex.Message), LogType.Error);
                    Utils.LogMessage(string.Format("WorkItemExplorerUserControl:projectToolStripComboBox_SelectedIndexChanged: Error initializing iterations and areas for selected project: {0}", ex.StackTrace), LogType.Error);
                    Utils.ShowErrorMessageBox(string.Format("Error initializing iterations and areas for selected project:\r\n\r\n{0}", ex.Message));
                }
                finally
                {
                    this.splitContainer1.Enabled = true;
                    Application.DoEvents();
                }
            }
        }

        private void areasTreeView_AfterSelect(object sender, TreeViewEventArgs e)
        {
            try
            {
                if (e.Node != null)
                {
                    this.PopulateResultsByArea(e.Node.FullPath);
                    e.Node.BackColor = Color.FromKnownColor(KnownColor.ActiveCaption);
                    e.Node.ForeColor = Color.FromKnownColor(KnownColor.ActiveCaptionText);
                }
            }
            catch (Exception ex)
            {
                Utils.LogMessage(string.Format("WorkItemExplorerUserControl:areasTreeView_AfterSelect: Error populating results for selected area: Message: {0}", ex.Message), LogType.Error);
                Utils.LogMessage(string.Format("WorkItemExplorerUserControl:areasTreeView_AfterSelect: Error populating results for selected area: {0}", ex.StackTrace), LogType.Error);
                Utils.ShowErrorMessageBox(string.Format("Error populating results for selected area:\r\n\r\n{0}",
                    ex.Message));
            }
        }

        private void iterationsTreeView_AfterSelect(object sender, TreeViewEventArgs e)
        {
            try
            {
                if (e.Node != null)
                {
                    this.PopulateResultsByIteration(e.Node.FullPath);
                    e.Node.BackColor = Color.FromKnownColor(KnownColor.ActiveCaption);
                    e.Node.ForeColor = Color.FromKnownColor(KnownColor.ActiveCaptionText);
                }
            }
            catch (Exception ex)
            {
                Utils.LogMessage(string.Format("WorkItemExplorerUserControl:iterationsTreeView_AfterSelect: Error populating results for selected iteration: Message: {0}", ex.Message), LogType.Error);
                Utils.LogMessage(string.Format("WorkItemExplorerUserControl:iterationsTreeView_AfterSelect: Error populating results for selected iteration: {0}", ex.StackTrace), LogType.Error);
                Utils.ShowErrorMessageBox(string.Format("Error populating results for selected iteration:\r\n\r\n{0}",
                    ex.Message));
            }
        }

        private void iterationsTreeView_BeforeSelect(object sender, System.Windows.Forms.TreeViewCancelEventArgs e)
        {
            try
            {
                if (this.iterationsTreeView.SelectedNode != null)
                {
                    this.iterationsTreeView.SelectedNode.BackColor = Color.Transparent;
                    this.iterationsTreeView.SelectedNode.ForeColor = Color.FromKnownColor(KnownColor.WindowText);
                }
            }
            catch (Exception ex)
            {
                Utils.LogMessage(string.Format("WorkItemExplorerUserControl:iterationsTreeView_BeforeSelect: Error selecting iteration: Message: {0}", ex.Message), LogType.Error);
                Utils.LogMessage(string.Format("WorkItemExplorerUserControl:iterationsTreeView_BeforeSelect: Error selecting iteration: {0}", ex.StackTrace), LogType.Error);
                Utils.ShowErrorMessageBox(string.Format("Error selecting iteration:\r\n\r\n{0}",
                    ex.Message));
            }
        }

        private void areasTreeView_BeforeSelect(object sender, System.Windows.Forms.TreeViewCancelEventArgs e)
        {
            try
            {
                if (this.areasTreeView.SelectedNode != null)
                {
                    this.areasTreeView.SelectedNode.BackColor = Color.Transparent;
                    this.areasTreeView.SelectedNode.ForeColor = Color.FromKnownColor(KnownColor.WindowText);
                }
            }
            catch (Exception ex)
            {
                Utils.LogMessage(string.Format("WorkItemExplorerUserControl:areasTreeView_BeforeSelect: Error selecting area: Message: {0}", ex.Message), LogType.Error);
                Utils.LogMessage(string.Format("WorkItemExplorerUserControl:areasTreeView_BeforeSelect: Error selecting area: {0}", ex.StackTrace), LogType.Error);
                Utils.ShowErrorMessageBox(string.Format("Error selecting area:\r\n\r\n{0}",
                    ex.Message));
            }
        }

        private void resultsDataGridView_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e)
        {
            if (_workItemCollection == null || _workItemCollection.Count == 0)
                return;

            if (e.RowIndex >= _workItemCollection.Count)
                return;

            // The first column is invisible.
            if (e.ColumnIndex == 0)
            {
                e.Value = string.Empty;
                return;
            }

            try
            {
                // Cache the work item in the Tag property for the row.
                //if (resultsDataGridView.Rows[e.RowIndex].Tag == null)
                //{
                //    Trace.WriteLine(string.Format("Tag[{0}] initialized.", e.RowIndex));
                //    resultsDataGridView.Rows[e.RowIndex].Tag = _workItemCollection[e.RowIndex];
                //}

                //int numberOfRows;
                //if (_workItemCollection.Count > _maxResultsDisplayed && _maxResultsDisplayed > 0)
                //    numberOfRows = _maxResultsDisplayed;
                //else
                //    numberOfRows = _workItemCollection.Count;

                // Set the cell's value.
                //bool newValue = false;

                if (_cachedItems == null)
                {
                    _cachedItems = new List<int>();
                }

                if (_cachedItems.Contains(e.RowIndex))
                {
                    // Use the store if the e value has been modified and stored.            
                    //e.Value = _gridStore[e.RowIndex][_queryColumns[e.ColumnIndex - 1]];
                    e.Value = _workItemCollection[e.RowIndex][_queryColumns[e.ColumnIndex - 1]];
                }
                else
                {
                    //newValue = true;
                    _cachedItems.Add(e.RowIndex);
                    e.Value = _workItemCollection[e.RowIndex][_queryColumns[e.ColumnIndex - 1]];
                }

                //Trace.WriteLine(string.Format("Cell[{0},{1}]={2}.{3}",
                //    e.RowIndex,
                //    e.ColumnIndex,
                //    e.Value,
                //    newValue ? " [New]" : string.Empty));
            }
            catch (Exception ex)
            {
                Utils.LogMessage(string.Format("WorkItemExplorerUserControl:resultsDataGridView_CellValueNeeded: Error initializing grid with results: Message: {0}", ex.Message), LogType.Error);
                Utils.LogMessage(string.Format("WorkItemExplorerUserControl:resultsDataGridView_CellValueNeeded: Error initializing grid with results: {0}", ex.StackTrace), LogType.Error);
                Utils.ShowErrorMessageBox(string.Format("Error initializing grid with results:\r\n\r\n{0}",
                    ex.Message));
            }
        }

        private void InitializeDataGrid()
        {
            this.resultsDataGridView.Rows.Clear();
            this.resultsDataGridView.Columns.Clear();
            _cachedItems = new List<int>(); // Reset the cache.

            // Add the columns.
            DisplayFieldList fieldList = _workItemCollection.Query.DisplayFieldList;
            _queryColumns = new string[fieldList.Count];

            this.resultsDataGridView.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] { this._id });

            //DataGridViewCell cellTemplate = this.resultsDataGridView.Rows[0].Cells[0];

            for (int i = 0; i < fieldList.Count; i++)
            {
                FieldDefinition field = fieldList[i];
                DataGridViewColumn columnHeader = new DataGridViewColumn(this.resultsDataGridView.Columns[0].CellTemplate);
                columnHeader.Name = field.ReferenceName;
                columnHeader.HeaderText = field.Name;
                //columnHeader.Width = field.Name.Length * 25;
                columnHeader.SortMode = DataGridViewColumnSortMode.Automatic;
                //this.resultsDataGridView.Columns.Add(field.ReferenceName, field.Name);
                this.resultsDataGridView.Columns.Add(columnHeader);
                _queryColumns[i] = field.ReferenceName;
            }

            // Hard-code the width of the ID and Title columns:
            this.resultsDataGridView.Columns[1].Width = 50; // ID
            this.resultsDataGridView.Columns[2].Width = 260; // Title
            this.resultsDataGridView.Columns[3].Width = 80; // State
            this.resultsDataGridView.Columns[6].Width = 120; // Created
            this.resultsDataGridView.Columns[7].Width = 120; // Updated
            this.resultsDataGridView.Columns[8].Width = 120; // Work Item Type
            this.resultsDataGridView.Columns[9].Width = 240; // Iteration/Area
            this.resultsDataGridView.Columns[10].Width = 240; // Area/Iteration

            // Initialize virtual mode handler and set virtual mode.
            this.resultsDataGridView.VirtualMode = true;
            this.resultsDataGridView.CellValueNeeded += new DataGridViewCellValueEventHandler(resultsDataGridView_CellValueNeeded);

            // Trigger virtual mode handler to start populating cells.
            if (_workItemCollection.Count > _maxResultsDisplayed && _maxResultsDisplayed > 0)
                this.resultsDataGridView.RowCount = _maxResultsDisplayed;
            else
                this.resultsDataGridView.RowCount = _workItemCollection.Count;

            UpdateResultsCount();
        }

        private void UpdateResultsCount()
        {
            this.countToolStripLabel.Text = string.Format(
                RESULTS_COUNT_TEMPLATE,
                this.resultsDataGridView.RowCount,
                (_workItemCollection == null) ? 0 : _workItemCollection.Count);
        }

        private void PopulateResultsByArea(string areaPath)
        {
            try
            {
                this.resultsSplitContainer.Enabled = false;
                this.queryToolStripProgressBar.Visible = true;

                _lastWiql = string.Format(AREAS_WIQL_TEMPLATE, _teamProjectName, areaPath);
                _workItemCollection = _store.Query(_lastWiql);

                this.pathToolStripTextBox.Text = areaPath;
                this.pathToolStripTextBox.Tag = "area";

                InitializeDataGrid();
            }
            catch (Exception ex)
            {
                Utils.LogMessage(string.Format("WorkItemExplorerUserControl:PopulateResultsByArea: Error running query: Message: {0}", ex.Message), LogType.Error);
                Utils.LogMessage(string.Format("WorkItemExplorerUserControl:PopulateResultsByArea: Error running query: {0}", ex.StackTrace), LogType.Error);
                Utils.ShowErrorMessageBox(string.Format("Error running query:\r\n\r\n{0}",
                    ex.Message));
            }
            finally
            {
                this.queryToolStripProgressBar.Visible = false;
                this.resultsSplitContainer.Enabled = true;
            }
        }

        private void PopulateResultsByIteration(string iterationPath)
        {
            try
            {
                this.resultsSplitContainer.Enabled = false;
                this.queryToolStripProgressBar.Visible = true;

                _lastWiql = string.Format(ITERATIONS_WIQL_TEMPLATE, _teamProjectName, iterationPath);
                _workItemCollection = _store.Query(_lastWiql);

                this.pathToolStripTextBox.Text = iterationPath;
                this.pathToolStripTextBox.Tag = "iteration";

                InitializeDataGrid();
            }
            catch (Exception ex)
            {
                Utils.LogMessage(string.Format("WorkItemExplorerUserControl:PopulateResultsByIteration: Error running query: Message: {0}", ex.Message), LogType.Error);
                Utils.LogMessage(string.Format("WorkItemExplorerUserControl:PopulateResultsByIteration: Error running query: {0}", ex.StackTrace), LogType.Error);
                Utils.ShowErrorMessageBox(string.Format("Error running query:\r\n\r\n{0}",
                    ex.Message));
            }
            finally
            {
                this.queryToolStripProgressBar.Visible = false;
                this.resultsSplitContainer.Enabled = true;
            }
        }

        // Copied from:
        // http://social.msdn.microsoft.com/Forums/en-US/tfsworkitemtracking/thread/51e142cb-b96f-448b-a482-1326f6bd5225
        // And corrected and modified to make it work.
        private void NodeCollectionToTreeNodeCollection(NodeCollection nodeCollection, TreeNodeCollection treeNodeCollection)
        {
            // add the root node (the team project):
            treeNodeCollection.Add(_teamProjectName, _teamProjectName, 0);
            treeNodeCollection[0].SelectedImageIndex = 0;

            foreach (Node node in nodeCollection)
            {
                treeNodeCollection[0].Nodes.Add(NodeToTreeNode(node));
            }

            treeNodeCollection[0].Expand();
        }

        // Copied from:
        // http://social.msdn.microsoft.com/Forums/en-US/tfsworkitemtracking/thread/51e142cb-b96f-448b-a482-1326f6bd5225
        // Used as is.
        // constructs a TreeNode from a node
        private TreeNode NodeToTreeNode(Node node)
        {
            TreeNode treeNode = new TreeNode(node.Name);
            treeNode.ImageIndex = 1;
            treeNode.SelectedImageIndex = 1;

            foreach (Node child in node.ChildNodes)
            {
                treeNode.Nodes.Add(NodeToTreeNode(child));
            }
            return treeNode;
        }

        private void areasRefreshToolStripButton_Click(object sender, EventArgs e)
        {
            try
            {
                this.areasTreeView.Enabled = false;
                if (_store != null && !string.IsNullOrEmpty(_teamProjectName))
                {
                    NodeCollection areaRootNodes = _store.Projects[_teamProjectName].AreaRootNodes;
                    this.InitializeAreas(areaRootNodes);
                }
            }
            catch (Exception ex)
            {
                Utils.LogMessage(string.Format("WorkItemExplorerUserControl:areasRefreshToolStripButton_Click: Error initializing: Message: {0}", ex.Message), LogType.Error);
                Utils.LogMessage(string.Format("WorkItemExplorerUserControl:areasRefreshToolStripButton_Click: Error initializing: {0}", ex.StackTrace), LogType.Error);
                Utils.ShowErrorMessageBox(string.Format("Error initializing:\r\n\r\n{0}", ex.Message));
            }
            finally
            {
                this.areasTreeView.Enabled = true;
            }
        }

        private void iterationsRefreshToolStripButton_Click(object sender, EventArgs e)
        {
            try
            {
                this.iterationsTreeView.Enabled = false;
                if (_store != null && !string.IsNullOrEmpty(_teamProjectName))
                {
                    NodeCollection iterationRootNodes = _store.Projects[_teamProjectName].IterationRootNodes;
                    this.InitializeIterations(iterationRootNodes);
                }
            }
            catch (Exception ex)
            {
                Utils.LogMessage(string.Format("WorkItemExplorerUserControl:iterationsRefreshToolStripButton_Click: Error initializing: Message: {0}", ex.Message), LogType.Error);
                Utils.LogMessage(string.Format("WorkItemExplorerUserControl:iterationsRefreshToolStripButton_Click: Error initializing: {0}", ex.StackTrace), LogType.Error);
                Utils.ShowErrorMessageBox(string.Format("Error initializing:\r\n\r\n{0}", ex.Message));
            }
            finally
            {
                this.iterationsTreeView.Enabled = true;
            }
        }

        private void maxResultsToolStripTextBox_TextChanged(object sender, EventArgs e)
        {
            try
            {
                if (this.maxResultsToolStripTextBox.Text.Trim().Length == 0)
                {
                    _maxResultsDisplayed = -1;
                    return;
                }

                int maxResults = Convert.ToInt32(this.maxResultsToolStripTextBox.Text.Trim());

                if (maxResults < 0)
                {
                    Utils.LogMessage(string.Format("WorkItemExplorerUserControl:maxResultsToolStripTextBox_Click: Maximum results threshold cannot be negative. Value specified: {0}.",
                        maxResults), LogType.Error);
                    Utils.ShowErrorMessageBox(string.Format("Maximum results threshold cannot be negative. Value specified: {0}.",
                        maxResults));
                    return;
                }

                if (maxResults == 0)
                {
                    Utils.LogMessage("WorkItemExplorerUserControl:maxResultsToolStripTextBox_Click: Maximum results threshold cannot be zero.", LogType.Error);
                    Utils.ShowErrorMessageBox("Maximum results threshold cannot be zero.");
                    return;
                }

                _maxResultsDisplayed = maxResults;
            }
            catch (Exception ex)
            {
                Utils.LogMessage(string.Format("WorkItemExplorerUserControl:maxResultsToolStripTextBox_Click: Error running query: Message: {0}", ex.Message), LogType.Error);
                Utils.LogMessage(string.Format("WorkItemExplorerUserControl:maxResultsToolStripTextBox_Click: Error running query: {0}", ex.StackTrace), LogType.Error);
                Utils.ShowErrorMessageBox(string.Format("Error setting maximum results threshold:\r\n\r\n{0}",
                    ex.Message));
            }
            finally
            {
                if (_maxResultsDisplayed > 0)
                    this.maxResultsToolStripTextBox.Text = _maxResultsDisplayed.ToString();
                else
                    this.maxResultsToolStripTextBox.Text = string.Empty;
            }
        }

        private void refreshToolStripButton_Click(object sender, EventArgs e)
        {
            try
            {
                // Refresh hosts.
                InitializeHosts();
            }
            catch (Exception ex)
            {
                Utils.LogMessage(string.Format("WorkItemExplorerUserControl:refreshToolStripButton_Click: Error refreshing TFS host names: Message: {0}", ex.Message), LogType.Error);
                Utils.LogMessage(string.Format("WorkItemExplorerUserControl:refreshToolStripButton_Click: Error refreshing TFS host names: {0}", ex.StackTrace), LogType.Error);
                Utils.ShowErrorMessageBox(string.Format("Error refreshing TFS host names:\r\n\r\n{0}", ex.Message));
            }
        }

        private void resultsDataGridView_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
        {
            if (e.RowIndex < 0 || e.ColumnIndex < 0)
                return;

            if (_magicKeyCombination)
            {
                _magicKeyCombination = false;
                //Form form = new WorkItemForm(_store, ((WorkItem)resultsDataGridView.Rows[e.RowIndex].Tag).Id);
                Form form = new WorkItemForm(_store, (_workItemCollection[e.RowIndex].Id));
                form.ShowDialog();
            }
            else
            {
                //ShowWorkItemForm((WorkItem) resultsDataGridView.Rows[e.RowIndex].Tag);
                ShowWorkItemForm(_workItemCollection[e.RowIndex]);
            }
        }

        private bool _magicKeyCombination = false;
        protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
        {
            const int WM_KEYDOWN = 0x100;
            const int WM_SYSKEYDOWN = 0x104;
            const int WM_KEYUP = 0x101;
            const int WM_SYSKEYUP = 0x105;

            if ((msg.Msg == WM_KEYUP) || (msg.Msg == WM_SYSKEYUP))
            {
                switch (keyData)
                {
                    case Keys.A | Keys.E | Keys.G:
                        _magicKeyCombination = false;
                        break;
                }
            }
            else if ((msg.Msg == WM_KEYDOWN) || (msg.Msg == WM_SYSKEYDOWN))
            {
                switch (keyData)
                {
                    case Keys.A | Keys.E | Keys.G:
                        _magicKeyCombination = true;
                        break;
                }
            }

            return base.ProcessCmdKey(ref msg, keyData);
        }

        private void ShowWorkItemForm(WorkItem workItem)
        {
            Trace.WriteLine(string.Format(CultureInfo.CurrentCulture, "ShowWorkItemForm: Entering WorkItemExplorerMenuItemCallback."));

            try
            {
                //ToolWindowPane pane = _package.FindToolWindow(typeof(WorkItemPane), 0, true);
                ToolWindowPane pane = _package.FindToolWindow(typeof(WorkItemPane), workItem.Id, true);

                if (pane == null)
                {
                    throw new COMException("Failed to initialize Work Item Explorer: Pane was null.");
                }
                pane.BitmapResourceID = 500;
                pane.BitmapIndex = 3;
                ((WorkItemPane)pane).WorkItem = workItem;

                IVsWindowFrame frame = pane.Frame as IVsWindowFrame;
                if (frame == null)
                {
                    throw new COMException("Failed to initialize Work Item Explorer: Frame was null.");
                }

                // Bring the tool window to the front and give it focus
                ErrorHandler.ThrowOnFailure(frame.Show());
            }
            catch (Exception ex)
            {
                Utils.LogMessage(string.Format("WorkItemExplorerUserControl:ShowWorkItemForm: Error displaying work item: Message: {0}", ex.Message), LogType.Error);
                Utils.LogMessage(string.Format("WorkItemExplorerUserControl:ShowWorkItemForm: Error displaying work item: {0}", ex.StackTrace), LogType.Error);
                Utils.ShowErrorMessageBox(string.Format("Error displaying work item:\r\n\r\n{0}", ex.Message));
            }
        }

        TcvtVsPackage _package = null;
        public TcvtVsPackage TcvtPackage
        {
            get
            {
                return _package;
            }
            set
            {
                _package = value;
            }
        }

        private void expandAllAreasToolStripButton_Click(object sender, EventArgs e)
        {
            if (this.areasTreeView.Nodes.Count > 0)
                this.areasTreeView.ExpandAll();
        }

        private void collapseAllAreasToolStripButton_Click(object sender, EventArgs e)
        {
            if (this.areasTreeView.Nodes.Count > 0)
                this.areasTreeView.CollapseAll();
        }

        private void expandAllIterationsToolStripButton_Click(object sender, EventArgs e)
        {
            if (this.iterationsTreeView.Nodes.Count > 0)
                this.iterationsTreeView.ExpandAll();
        }

        private void collapseAllIterationsToolStripButton_Click(object sender, EventArgs e)
        {
            if (this.iterationsTreeView.Nodes.Count > 0)
                this.iterationsTreeView.CollapseAll();
        }

        private void refreshResultsToolStripButton_Click(object sender, EventArgs e)
        {
            if (this.pathToolStripTextBox.Tag != null)
            {
                switch ((string)this.pathToolStripTextBox.Tag)
                {
                    case "area":
                        this.PopulateResultsByArea(this.pathToolStripTextBox.Text);
                        break;
                    case "iteration":
                        this.PopulateResultsByIteration(this.pathToolStripTextBox.Text);
                        break;
                    default:
                        return;
                }
            }
        }

        private void InitializePackage()
        {
            // Dynamically load the buddy build package.
            IVsShell shell = Package.GetGlobalService(typeof(SVsShell)) as IVsShell;
            if (shell == null)
            {
                MessageBox.Show("Failed to initialize shell. Please launch Work Item Explorer from the BuddyBuild menu.",
                                "Work Item Explorer",
                                MessageBoxButtons.OK,
                                MessageBoxIcon.Error);

                return;
            }

            IVsPackage tcvtPackage = null;
            Guid tcvtPackageGuid = new Guid(GuidList.guidTfsBuggerVSPackagePkgString);
            int loadPackageResult = shell.LoadPackage(ref tcvtPackageGuid, out tcvtPackage);

            _package = tcvtPackage as TcvtVsPackage;

            _package.InitializeOptions();
        }
    }
}
